import 'package:flutter/material.dart';

class ModelBindingV2<T> extends StatefulWidget {
  ModelBindingV2({Key key, @required this.create, this.child})
      : assert(create != null),
        super(key: key);
  final ValueGetter<T> create;
  final Widget child;

  @override
  _ModelBindingV2State<T> createState() => _ModelBindingV2State<T>();

  static T of<T>(BuildContext context) {
    _ModelBindingScope<T> scope =
        context.dependOnInheritedWidgetOfExactType(aspect: _ModelBindingScope);
    return scope.modelBindingState.currentModel;
  }

  static void update<T>(BuildContext context, T newModel) {
    _ModelBindingScope<T> scope =
        context.dependOnInheritedWidgetOfExactType(aspect: _ModelBindingScope);
    scope.modelBindingState.updateModel(newModel);
  }
}

class _ModelBindingV2State<T> extends State<ModelBindingV2<T>> {
  T currentModel;
  @override
  void initState() {
    super.initState();
    currentModel = widget.create();
  }

  void updateModel(T newModel) {
    if (currentModel != newModel) {
      setState(() {
        currentModel = newModel;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return _ModelBindingScope<T>(
      modelBindingState: this,
      child: widget.child,
    );
  }
}

class ViewModel {
  final int value;
  const ViewModel({this.value = 0});

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    if (other.runtimeType != runtimeType) {
      return false;
    }
    final ViewModel otherModel = other;
    return otherModel.value == value;
  }

  @override
  int get hashCode => value.hashCode;
}

class _ModelBindingScope<T> extends InheritedWidget {
  _ModelBindingScope({
    Key key,
    @required this.modelBindingState,
    Widget child,
  })  : assert(modelBindingState != null),
        super(key: key, child: child);

  final _ModelBindingV2State<T> modelBindingState;

  @override
  bool updateShouldNotify(_ModelBindingScope oldWidget) => true;
}
